﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Agrement;
using IIControls.IAControl;
using System.Web.Script.Serialization;
namespace Communicate
{
   public  class AgreePrivate
    {
        public AgreePrivate() { }

        /// <summary>
        /// 协议选择
        /// 0：COM口发送,协调器发送
        /// 1：COM口发送，通过GPRS发送
        /// 2：TCP口发送，通过电脑网络协议
        /// </summary>
        public int AgreeMentSelect { get; set; }

        public AgreePrivate (del_Send SendBytes, string GCode="",int  AgreeSelect=2)
        {
            Send = SendBytes;
            T = new System.Timers.Timer(15000);
            T.Elapsed += T_Elapsed;
            GPRSCode = GCode;
            AgreeMentSelect = AgreeSelect;
        }

        /// <summary>
        /// 协调器编号
        /// </summary>
        public int CoorId { get; set; }

        /// <summary>
        /// GPRS编号
        /// </summary>
        public string  GPRSCode { get; set; }

        /// <summary>
        /// 超时时钟，多久未返回数据视为超时
        /// </summary>
        System.Timers.Timer T;


        /// <summary>
        /// 按时间顺序记录任务表
        /// </summary>
        public  List<TaskMsg> Tasks = new List<IIControls.IAControl.TaskMsg>();


        /// <summary>
        /// 增加一个任务
        /// </summary>
        /// <param name="TM"></param>
        internal  void  ADDTaskMsg(TaskMsg TM)
        {
            Tasks.Add(TM);
        }
        /// <summary>
        /// 减少一个任务
        /// </summary>
        /// <param name="TM"></param>
        internal void  DELTaskMsg(TaskMsg TM)
        {
            if(Tasks.Contains(TM))
            Tasks.Remove(TM);
        }

        /// <summary>
        /// 移除所有任务
        /// </summary>
        internal bool  RemoveAllMsg()
        {
            if (TaskIsStart)
                return false;
            else
            {
                Tasks.Clear();
                return true;
            }

        }

        Send_Agreement SA = new Send_Agreement();
        JSON_Private TCPAgreeMent = new JSON_Private();

        public  bool TaskIsStart = false;

        #region 队列任务相关
        /// <summary>
        /// 多次任务内容
        /// </summary>
       public   List<TaskMsg[]> TaskPackage = new List<TaskMsg[]>();

        /// <summary>
        /// 一次任务内容
        /// </summary>
       public  List<TaskMsg> onePackage =new List<TaskMsg>();
        /// <summary>
        /// 开始执行任务
        /// </summary>
        internal async void SendTasks()
        {
            if (TaskIsStart == true)
                return;
            TaskIsStart = true;
            //允许的最大打包数量
            const int MaxPackNum = 9;
            //当前打包个数
            int NowCount = 0;
          
            List<byte> SendData = new List<byte>();

            //协调器编号
            int CorID = 0;

            List<CMD> TcpSendlist = new List<CMD>();
           
            for (int i = 0; i < Tasks.Count; i++)
            {
                NowCount++;
                TaskMsg task = Tasks[i];
                onePackage.Add(task);
                task.TaskIsRun = true;             
                //数据帧中带入的数据
                List<byte> Data = new List<byte>();
                //功能码
                byte Oper = 0;
                //获得设备类型
                byte DeviceCode = 0;
                if (task.DeviceAllMsg.GetType() == typeof(ValveControl))
                    DeviceCode = 1;
                else if (task.DeviceAllMsg.GetType() == typeof(PumpControl))
                    DeviceCode = 4;
                int DeviceId = 0;
                switch (DeviceCode)
                {
                    case 1:  //太阳能控制器
                        ValveControl VC = (ValveControl)task.DeviceAllMsg;
                        //获取GPRS编号
                        GPRSCode = VC.Valveinit.GPRSNumber;
                        CorID = Convert.ToInt32(VC.Valveinit.CoorNumber);
                        int valvenumber;
                        DeviceId = Convert.ToInt32(VC.ValveId.Substring(2, VC.ValveId.Length - 3));
                        valvenumber = Convert.ToInt32(VC.ValveId.Substring(VC.ValveId.Length - 1, 1));
                        CorID = Convert.ToInt32(VC.Valveinit.CoorNumber);
                        ValveControl.ClickType CT = (ValveControl.ClickType)task.CmdType;
                        switch (CT)
                        {
                            case ValveControl.ClickType.ValveOpen:
                                Oper = (byte)(valvenumber * 2 - 1 + 0x30);
                                break;
                            case ValveControl.ClickType.ValveClose:
                                Oper = (byte)(valvenumber * 2 + 0x30);
                                break;
                            case ValveControl.ClickType.ValveCheckeStatue:
                                Oper = 0x39;
                                break;
                            case ValveControl.ClickType.ValveCheckeVoltage:
                                Oper = 0x3A;
                                break;
                            case ValveControl.ClickType.ValveInit:
                                DeviceCode = 3;
                                Oper = 2;
                                Data.Add((byte)(DeviceId / 256));
                                Data.Add((byte)(DeviceId % 256));
                                Data.Add(4);
                                Data.Add(Convert.ToByte(VC.ValveId.Substring(0, 2)));
                                break;
                        }
                        break;
                    case 4:   //泵房控制器
                        PumpControl PC = (PumpControl)Tasks[i].DeviceAllMsg;
                        GPRSCode = PC.Pumpinits.GPRSNumber;
                        CorID = Convert.ToInt32(PC.Pumpinits.CoorNumber);
                        DeviceId = Convert.ToInt32(PC.PumpId.Substring(2, PC.PumpId.Length-2));
                        CorID = Convert.ToInt32(PC.Pumpinits.CoorNumber);
                        PumpControl.ClickType PT = (PumpControl .ClickType)Tasks[i].CmdType;
                        switch (PT)
                        {
                            case PumpControl.ClickType.Channel1Open:
                                Oper = 1;
                                break;
                            case PumpControl.ClickType.Channel1Close:
                                Oper = 2;
                                break;
                            case PumpControl.ClickType.Channel2Open:
                                Oper = 3;
                                break;
                            case PumpControl.ClickType.Channel2Close:
                                Oper = 4;
                                break;
                            case PumpControl.ClickType.Channel3Open:
                                Oper = 5;
                                break;
                            case PumpControl.ClickType.Channel3Close:
                                Oper = 6;
                                break;
                            case PumpControl.ClickType.ValveOpen:
                                Oper = 7;
                                break;
                            case PumpControl.ClickType.ValveClose:
                                Oper = 8;
                                break;
                            case PumpControl.ClickType.Pump1Open:
                                Oper = 9;
                                break;
                            case PumpControl.ClickType.Pump1Close:
                                Oper = 10;
                                break;
                            case PumpControl.ClickType.Pump2Open:
                                Oper = 11;
                                break;
                            case PumpControl.ClickType.Pump2Close:
                                Oper = 12;
                                break;
                            case PumpControl.ClickType.CheckStatue:
                                Oper = 13;
                                break;
                            case PumpControl.ClickType.FrontPress:
                                Oper = 14;
                                break;
                            case PumpControl.ClickType.SyncTime:
                                Data.Add(DateTimeConvert(DateTime.Now.Year%2000 ));
                                Data.Add(DateTimeConvert(DateTime.Now.Month));
                                Data.Add(DateTimeConvert(DateTime.Now.Day));
                                Data.Add(DateTimeConvert(DateTime.Now.Hour));
                                Data.Add(DateTimeConvert(DateTime.Now.Minute));
                                Data.Add(DateTimeConvert(DateTime.Now.Second));
                                Oper = 16;
                                break;
                            case PumpControl.ClickType.ReadRecord:
                                Oper = 17;
                                break;
                            case PumpControl.ClickType.ClearRecord:
                                Oper = 18;
                                break;
                            case PumpControl.ClickType.ReadTime:
                                Oper = 21;
                                break;
                            case PumpControl.ClickType.PumpInit:
                                DeviceCode = 6;
                                Oper = 2;
                                Data.Add((byte)(DeviceId / 256));
                                Data.Add((byte)(DeviceId % 256));
                                Data.Add(4);
                                int Devicebh = Convert.ToInt32(PC.PumpId.Substring(0, 2));
                                Data.Add((byte)Devicebh);
                                break;
                        }
                        break;
                }
                CoorId = CorID;
                SendData.Add((byte)(DeviceId / 256));
                SendData.Add((byte)(DeviceId % 256));

                switch (AgreeMentSelect)
                {
                    case 0:
                        SendData.AddRange(SA.Make_AgreementCenter(DeviceCode, Oper, new int[] { 0 }, Data.ToArray()));
                        break;
                    case 1:
                    case 2 :
                        CMD TcpSendCmd = new CMD();
                        TcpSendCmd.device_cmd = Oper;
                        TcpSendCmd.device_type = DeviceCode;
                        TcpSendCmd.device_code = new int[] { 0 };
                        TcpSendCmd.device_data = Data.ToArray();
                        TcpSendCmd.wirless_code = DeviceId;
                        TcpSendlist.Add(TcpSendCmd);
                        break;
                }


                //条数达到PackNum就发送出去
                if (NowCount == MaxPackNum)
                {
                    //记录开始位置
                    //StartCount += PackCount;
                    //PackCount = NowCount;
                    NowCount = 0;
                    if (AgreeMentSelect == 0)
                    {
                        SDStru.DeviceType = 10;
                        SDStru.Oper = 1;
                        SDStru.Ids = new int[] { CorID };
                        SDStru.Data = SendData;
                        await AutoSendMsg();
                    }
                    else if (AgreeMentSelect == 1 || AgreeMentSelect == 2)
                    {
                        SDStru.DeviceType = 10;
                        SDStru.Oper = 1;
                        SDStru.Ids = new int[] { CorID };
                        SDStru.Data = SendData;
                        SDStru.cmd = TcpSendlist;
                        await AutoSendMsg();
                        TcpSendlist.Clear();
                    }
                    //SendData.Clear();
                }
            }
            Tasks.Clear();
            //未满PackNum的发送出去
            if (NowCount != 0)
            {
                //记录开始位置
                //StartCount += PackCount;
                //PackCount = NowCount;
                NowCount = 0;
                if (AgreeMentSelect == 0)
                {
                    SDStru.DeviceType = 10;
                    SDStru.Oper = 1;
                    SDStru.Ids = new int[] { CorID };
                    SDStru.Data = SendData;
                    await AutoSendMsg();
                }

                else if (AgreeMentSelect == 2 || AgreeMentSelect == 1)
                {
                    SDStru.DeviceType = 10;
                    SDStru.Oper = 1;
                    SDStru.Ids = new int[] { CorID };
                    SDStru.Data = SendData;
                    SDStru.cmd = TcpSendlist;
                    await AutoSendMsg();
                }
            }
            TaskIsStart = false;
            //如果还加入了任务
            if (Tasks.Count > 0)
                SendTasks();
            //StartCount = 0;
            //PackCount = 0;
        }

        /// <summary>
        /// 要发送的数据包
        /// </summary>
        SendDataStru SDStru = new SendDataStru();

        /// <summary>
        /// 数据包格式
        /// </summary>
        struct SendDataStru
        {
            public byte DeviceType;
            public byte Oper;
            public int[] Ids;
            public List<byte> Data;
            public List<CMD> cmd;
        }

        /// <summary>
        /// 自动重发
        /// </summary>
        private Task AutoSendMsg()
        {
            return Task.Run (() =>
            {

                List<byte> info = new List<byte>();
                switch (AgreeMentSelect)
                {
                    case 0:
                        info.AddRange(SA.Make_AgreementCenter(SDStru.DeviceType, SDStru.Oper, SDStru.Ids, SDStru.Data.ToArray()));
                        break;
                    case 1:
                    case 2:
                        TCPAgreeMent.coord_code = SDStru.Ids[0];
                        TCPAgreeMent.coord_cmd = SDStru.Oper.ToString();
                        TCPAgreeMent._list = SDStru.cmd.ToArray();
                        TCPAgreeMent.network_way = "0";
                        TCPAgreeMent.gprs_code = GPRSCode;
                        JavaScriptSerializer javas = new JavaScriptSerializer();
                        string SerialString = javas.Serialize(TCPAgreeMent);
                        info.AddRange( System.Text.Encoding.Default.GetBytes(SerialString));
                        break;
                }
                TaskPackage.Add(onePackage.ToArray());
                onePackage.Clear();
                Send(info.ToArray());
                locks = 0;
                T.Start();
                int returnres = asyncwaitback();
                if (returnres == 2)
                {
                    Send(info.ToArray());
                    locks = 0;
                    T.Stop();
                    T.Start();
                    asyncwaitback();
                }
                SDStru.Data.Clear();

               
            });
        }


        internal void  clearstatue(TaskMsg[] tm)
        {
            for (int i = 0; i < tm.Length; i++)
                if(tm[i].TaskIsRun )
                    switch (tm[i].DeviceType )
                    {
                        case 0:
                        BusTransfer.MsgTransfer.Instance.Send((object)((ValveControl.ClickType)tm[i].CmdType), "v_" +((ValveControl) tm[i].DeviceAllMsg).Valveinit.GPRSNumber  + tm[i].DeviceId);
                            break;
                        case 1:
                            BusTransfer.MsgTransfer.Instance.Send((object)((PumpControl.ClickType )tm[i].CmdType), "v_" + ((PumpControl )tm[i].DeviceAllMsg).Pumpinits .GPRSNumber + tm[i].DeviceId);
                            break;

                    }
                

        }

        /// <summary>
        /// 等待回复
        /// 0:等待数据返回
        /// 1：正常返回
        /// 2：超时返回
        /// </summary>
        internal int locks = 0;


        /// <summary>
        /// 等待数据返回
        /// </summary>
        /// <returns></returns>
        private int asyncwaitback()
        {
            while (true)
            {
                System.Threading.Thread.Sleep(1);
                if (locks > 0)
                    return locks;
            }
        }

        /// <summary>
        /// 超时后吧locks写成2
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            locks = 2;
            foreach (TaskMsg  tm in Tasks)
            {
                if (tm.TaskIsRun)
                    tm.TaskIsRun = false;
                else
                    tm.TaskIsRun = true;
            }
            if(TaskPackage.Count>0)
            TaskPackage.RemoveAt(0);
            ((System.Timers.Timer)sender).Stop();
        }


        /// <summary>
        /// 10进制使用16进进行输出
        /// </summary>
        /// <param name="Times"></param>
        /// <returns></returns>
        private byte DateTimeConvert(int Times)
        {
            int TH = Times / 10;
            int TL = Times % 10;

            return (byte)(TH * 16 + TL);
        } 
        #endregion

        /// <summary>
        /// 调用接口进行数据的发送
        /// </summary>
        del_Send  Send;

       public  delegate void del_Send(byte[] data);


        #region 发送即时任务
        /// <summary>
        /// 发送即时任务，比如重启协调器，收到全部操作成功或操作失败打包后的数据回复
        /// </summary>
        /// <param name="gprs">GPRS编号</param>
        /// <param name="types">设备类型（固定：10）</param>
        /// <param name="oper">操作</param>
        /// <param name="ids">协调器编号</param>
        /// <param name="datas">要传入的数据</param>
        public void  sendImmediatelyTask(string gprs,byte types, byte oper, int[] ids, byte[] datas)
        {
            List<byte> SendByte = new List<byte>();
             switch( AgreeMentSelect)
            {
                case 0:
                    if (gprs != "")
                        SendByte.AddRange(System.Text.Encoding.Default.GetBytes(gprs));
                    SendByte.AddRange(SA.Make_AgreementCenter(types, oper, ids, datas));
                    break;
                case 1:
                case 2:
                    TCPAgreeMent.coord_code = ids[0];
                    TCPAgreeMent.coord_cmd = oper.ToString();
                    TCPAgreeMent.coor_type = types.ToString();
                    TCPAgreeMent._list = null;
                    TCPAgreeMent.network_way = "0";
                    TCPAgreeMent.gprs_code = gprs;
                    JavaScriptSerializer javas = new JavaScriptSerializer();
                    string SerialString = javas.Serialize(TCPAgreeMent);
                    SendByte.AddRange(System.Text.Encoding.Default.GetBytes(SerialString));
                    break;
            }
            Send( SendByte.ToArray());

        }
        #endregion
    }
}
